/**
 * \file
 */
#ifndef AUX_NODE_EDGE_H
#define AUX_NODE_EDGE_H

#include "../network/network.h"
#include "../network/edge.h"
#include "../network/node.h"

/* Nodo auxiliar */
typedef struct sNodeANet *nodeANet;
/* Arista auxiliar */
typedef struct sEdgeANet *edgeANet;

/********************************** Nodo *************************************/

/**
 * Crea un nuevo nodo.
 * \param n Nodo al cual apuntaremos.
 * \param level Nivel dentro del network auxiliar donde fue creado el nodo.
 * \return Nuevo nodo en el network auxiliar.
 */
nodeANet nodeANet_create(const node n, const int level);

/**
 * Destruye un nodo del network auxiliar.
 * \param n Nodo a destruir.
 * \return NULL
 */
nodeANet nodeANet_destroy(nodeANet nANet);

/**
 * Devuelve el puntero al nodo en el network original.
 * \param nANet Nodo del network auxiliar.
 * \return Nodo en el network original..
 */
node nodeANet_getNode(const nodeANet nANet);

/**
 * Agrega un vecino al nodo 'nANet'.
 * Requiere que 'e' no sea un vecino de 'nANet'.
 * \param nANet Nodo de orígen de la arista.
 * \param e Lado que va a ser agregado a los lados que parten desde 'nANet'.
 */
void nodeANet_addNeighbor(nodeANet nANet, const edgeANet e);

/**
 * Borra a la arista 'e' de los vecinos del nodo 'nANet'.
 * 
 * \param nANet Nodo de orígen de la arista.
 * \param e Lado que va a ser borrado de lados que parten desde x.
 */
void nodeANet_delNeighbor(nodeANet nANet, edgeANet e);

/**
 * Obtiene el vecino del nodo 'nANet' identificado por la etiqueta 'label'.
 * \param nANet Nodo de orígen.
 * \param label Etiqueta del nodo de destino.
 * \return Nodo de destino o NULL si no se encontró.
 */
nodeANet nodeANet_getNeighbor(const nodeANet nANet, const unsigned int label);

/**
 * Obtiene todos los vecinos del nodo 'nANet'.
 * \param nANet Nodo del network auxiliar.
 * \return Lista de aristas que parten desde 'nANet' hacia el siguiente nivel.
 */
GList *nodeANet_getNeighbors(const nodeANet nANet);

/* EFICIENCIA */
/**
 * Setea la lista de vecinos del nodo 'nANet'.
 * \param nANet Nodo del network auxiliar.
 * \param Lista de aristas que parten desde 'nANet' hacia el siguiente nivel.
 */
void nodeANet_setNeighbors(nodeANet nANet, GList *neighbors);

/**
 * Devuelve la etiqueta de un nodo.
 * \param nANet Nodo.
 * \return Etiqueta del nodo.
 */
unsigned int nodeANet_getLabel(const nodeANet nANet);

/**
 * Devuelve el nivel del nodo 'nANet'
 * \param nANet Nodo
 * \return Nivel del network auxiliar en el que se encuentra el nodo.
 */
int nodeANet_getLevel(const nodeANet nANet);

/**
 * Usada para Debug. Imprime información acerca del nodo.
 * \param nANet Nodo del network auxiliar.
 */
void nodeANet_print(const nodeANet nANet);

/********************************* Arista ************************************/

/**
 * Crea una nueva arista.
 * \param e Arista del network original.
 * \param dst Puntero al nodo destino de la arista.
 * \param forward Indica si la arista es forward o backward.
 * \return Nueva arista.
 */
edgeANet edgeANet_create(const edge e, const nodeANet dst, const bool forward);

/**
 * Destruye una arista. 
 * \param eANet Arista a borrar.
 * \return NULL
 */
edgeANet edgeANet_destroy(edgeANet eANet);

/**
 * Devuelve la arista original.
 * \param eANet Arista en el network auxiliar.
 * \return la arista del network original relacionada a eANet.
 */
edge edgeANet_getEdge(const edgeANet eANet);

/**
 * Devuelve la capacidad de la arista 'eANet'.
 * \param eANet Arista en el network auxiliar.
 * \return capacidad de la arista en el network original.
 */
unsigned int edgeANet_getCap(const edgeANet eANet);

/**
 * Devuelve el flujo de la arista 'eANet'.
 * \param eANet Arista en el network auxiliar.
 * \return flujo de la arista en el network original.
 */
unsigned int edgeANet_getFlow(const edgeANet eANet);

/**
 * Incrementa el flujo de la arista 'eANet' en 'flow'.
 * \param eANet Arista a la que quiero incrementarle su flujo.
 * \param flow Incremento en el flujo.
 */
void edgeANet_increaseFlow(edgeANet eANet, const unsigned int flow);

/**
 * Decrementa el flujo de la arista 'eANet' en 'flow'.
 * \param eANet Arista a la que quiero decrementarle su flujo.
 * \param flow Decremento en el flujo.
 */
void edgeANet_decreaseFlow(edgeANet eANet, const unsigned int flow);

/**
 * Indica si una arista está saturada.
 * \param e Arista del network auxiliar.
 * \return True si está saturada o False si no lo está.
 */
bool edgeANet_isSaturated(const edgeANet eANet);

/**
 * Indica si una arista tiene flujo.
 * \param e Arista del network auxiliar.
 * \return True si tiene flujo o False si no tiene.
 */
bool edgeANet_isEmpty(const edgeANet eANet);

/**
 * Devuelve el nodo de destino de la arista 'eANet'.
 * \param eANet Arista del network auxiliar.
 * \return Nodo destino de la arista.
 */
nodeANet edgeANet_getNeighbor(const edgeANet eANet);

/**
 * Indica si la arista 'eANet' es Forward en el network original.
 * \param eANet Arista del network auxiliar.
 * \return True si es Forward en el network original o False si es Backward.
 */
bool edgeANet_isForwardInNetwork(const edgeANet eANet);

/**
 * Usada para Debug. Imprime información acerca de la arista.
 * \param eANet Arista del network auxiliar.
 */
void edgeANet_print(const edgeANet eANet);

#endif

